/*
 </samplecode>
*/

#include "echoTouchHelper.h"

void LoadVoiceFileDataToMemory(CFURLRef inURL,
                               AudioStreamBasicDescription &outFileDesc,
                               UInt64 &outFileSize,
                               void* &outFileData)
{
	outFileData = NULL;
	AudioFileID afid = 0;
	UInt32 propSize;
	 
	OSStatus result = AudioFileOpenURL(inURL, kAudioFileReadPermission, 0, &afid);
	
	if (result) {
		printf("ERROR LOADING FILE: %d\n", (int)result);
		goto fail;
	}
	
	propSize = sizeof(outFileSize);
	result = AudioFileGetProperty(afid, kAudioFilePropertyAudioDataByteCount, &propSize, &outFileSize);
	if (result) {
		printf("ERROR GETTING FILE SIZE: %d\n", (int)result);
		goto fail;
	}

	propSize = sizeof(outFileDesc);
	result = AudioFileGetProperty(afid, kAudioFilePropertyDataFormat, &propSize, &outFileDesc);
	if (result) {
		printf("ERROR GETTING FILE STREAM DESCRIPTION: %d\n", (int)result);
		goto fail;
	}
	
	outFileData = malloc(outFileSize);
	
	UInt32 bytesToRead;
    
    bytesToRead = (UInt32)outFileSize;
	result = AudioFileReadBytes(afid, false, 0, &bytesToRead, outFileData);
	if (result || (bytesToRead != outFileSize)) {
		printf("ERROR READING FILE AUDIO DATA: %d\n", (int)result);
		goto fail;
	}

	result = AudioFileClose(afid);
	if (result) printf("ERROR CLOSING FILE: %d\n", (int)result);
	
	return;
    
fail:
	if (outFileData) free(outFileData);
	if (afid) AudioFileClose(afid);
	outFileSize = 0;
	outFileData = NULL;
    
	return;
}

OSStatus SetupOutputUnit(AURenderCallbackStruct inInputProc, 
						 AURenderCallbackStruct inRenderProc,
                         AudioUnit &outUnit,
						 const AudioStreamBasicDescription &voiceIOFormat)
{
	OSStatus result = noErr;
	
    /**  初始化描述  **/
	// Open the output unit
    AudioComponentDescription desc = { kAudioUnitType_Output,               // type
                                       kAudioUnitSubType_VoiceProcessingIO, // subType设置这货，可以默认开启回声消除
                                       kAudioUnitManufacturer_Apple,        // manufacturer
                                       0, 0 };                              // flags
        
	AudioComponent comp = AudioComponentFindNext(NULL, &desc);
	
    /**  创建audio unit  **/
	result = AudioComponentInstanceNew(comp, &outUnit);
	if (result) {
		printf("couldn't open the audio unit: %d", (int)result);
		goto end;
	}

    /**  添加属性，允许输入（录音）  **/
    UInt32 one; one = 1; //TM的，直接写UInt32 one = 1;上面的goto end报错
    AudioUnitElement inputBus; inputBus = 1;
	result = AudioUnitSetProperty(outUnit,
                                  kAudioOutputUnitProperty_EnableIO,
                                  kAudioUnitScope_Input,
                                  inputBus,//这个1，表示是bus 1（总线1 ???）,目测官网上的输入就是1，输出是0
                                  &one,//这个1，表示允许，0不允许
                                  sizeof(one));
	if (result) {
		printf("couldn't enable input on the audio unit");
		goto end;
	}
	
    /**  添加属性，输入回调  **/
	result = AudioUnitSetProperty(outUnit,
                                  kAudioOutputUnitProperty_SetInputCallback,
                                  kAudioUnitScope_Global,
                                  inputBus,//从bus 1获取数据
                                  &inInputProc,//回调方法(AURenderCallback)的指针，这里弄了个struct，用于保存更多数据，回调方法的函数指针必须在第一个
                                  sizeof(inInputProc));
	if (result) {
		printf("couldn't set audio unit input proc");
		goto end;
	}

    /**  添加属性，输入音频渲染回调，文档中写的这是有渲染模式，可以在回调中搞些事情，先回调这个，在回调input的，但回调中最好不要加锁或干些对性能有影响的操作  **/
	result = AudioUnitSetProperty(outUnit,
                                  kAudioUnitProperty_SetRenderCallback,
                                  kAudioUnitScope_Input,
                                  0,
                                  &inRenderProc,
                                  sizeof(inRenderProc));
	if (result) {
		printf("couldn't set audio render callback");
		goto end;
	}

    /**  添加属性，设置采集音频的属性  **/
	result = AudioUnitSetProperty(outUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Input,
                                  0,    //这个0还不太理解，目测所有的kAudioUnitScope_Input都是0，output都是1
                                  &voiceIOFormat,
                                  sizeof(voiceIOFormat));
	if (result) {
		printf("couldn't set the audio unit's output format");
		goto end;
	}
	
    /**  添加属性，设置输出音频的属性  **/
	result = AudioUnitSetProperty(outUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Output,
                                  1,
                                  &voiceIOFormat,
                                  sizeof(voiceIOFormat));
	if (result) {
		printf("couldn't set the audio unit's input client format");
		goto end;
	}
	
    /**  在你改变音频单元的特性之前，例如改变输入输出流的格式或者采样率，你必须先取消其初始化。调用这个方法来释放音频对象资源。调用这个方法后你可以重新配置音频参数并且重新初始化  **/
	result = AudioUnitInitialize(outUnit);
	if (result) {
		printf("couldn't initialize the audio unit");
		goto end;
	}
                                   
end:
	return result;
}
